const Redis = require('ioredis')
const lodash = require('lodash')
const readline = require('readline')

// redis服务器ip地址
let host = '127.0.0.1'
// redis端口
let port = '6379'
// redis密码
let pwd = ''
// redis数据库
let db = 1
// 保留排行前多少key
let leng = 10
// 是否打印scan的游标
let showLog = true

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
})

// 函数用于获取所有键的内存大小并返回最大的
function findLargestKey() {
  return new Promise(async (resolve, reject) => {
    let cursor = '0'
    let end = false
    let keys = []
    // 创建Redis客户端实例
    const redis = new Redis({
      host: host,
      port: port,
      db: db,
      password: pwd // 如果有密码的话
    })
    console.log('连接redis中...')
    redis.on('error', (err) => {
      redis.quit()
      reject('Redis连接失败，请确认信息后重试！')
    })
    do {
      const scanResult = await redis.scan(cursor, 'MATCH', '*', 'COUNT', 100)
      if (cursor === '0') {
        console.log('连接redis成功')
      }
      cursor = scanResult[0]
      if (showLog) {
        console.log('scan游标：' + cursor)
      }
      const data = scanResult[1]
      for (const key of data) {
        const size = await redis.memory('usage', key)
        if (keys.length < leng) {
          keys.push({ key: key, B: size })
          keys = lodash.orderBy(keys, ['B'], ['desc'])
        } else {
          if (size > keys[leng - 1].size) {
            keys.push({ key: key, B: size })
            keys = lodash.orderBy(keys, ['B'], ['desc'])
            keys.pop()
          }
        }
      }
      end = cursor === '0'
    } while (!end)
    resolve(keys)
  })
}

// 提示输入redis的host
const readHost = function () {
  return new Promise((resolve) => {
    rl.question('请输入Redis服务host(默认127.0.0.1)：', (answer) => {
      let host = answer.trim().toLocaleUpperCase()
      if (host === '') {
        console.log('使用默认host值：127.0.0.1')
        host = '127.0.0.1'
      } else {
        console.log('您输入的host是：' + host)
      }
      resolve(host)
    })
  })
}

// 提示输入redis的port
const readPort = function () {
  return new Promise((resolve, reject) => {
    rl.question('请输入Redis服务端口(默认6379)：', (answer) => {
      let port = answer.trim().toLocaleUpperCase()
      if (port === '') {
        console.log('使用默认端口值：6379')
        port = '6379'
      } else {
        console.log('您输入的端口是：' + port)
      }
      resolve(port)
    })
  })
}

// 提示输入redis的密码
const readPwd = function () {
  return new Promise((resolve, reject) => {
    rl.question('请输入Redis服务密码(默认空)：', (answer) => {
      let pwd = answer.trim().toLocaleUpperCase()
      if (pwd === '') {
        console.log('使用默认密码值：空')
        pwd = ''
      } else {
        console.log('您输入的密码是：' + pwd)
      }
      resolve(pwd)
    })
  })
}

// 提示输入redis的Db
const readDb = function () {
  return new Promise((resolve, reject) => {
    rl.question('请输入需要检索的DB(默认0)：', (answer) => {
      let db = answer.trim().toLocaleUpperCase()
      if (db === '') {
        console.log('使用默认DB值：0')
        db = 0
      } else {
        console.log('您输入的DB是：' + db)
      }
      resolve(db)
    })
  })
}

// 提示输入排行前多少
const readLeng = function () {
  return new Promise((resolve, reject) => {
    rl.question('请输入需要检索排行前多少条(默认10)：', (answer) => {
      let val = answer.trim().toLocaleUpperCase()
      if (val === '') {
        console.log('使用默认统计排行前：10条')
        val = 10
      } else {
        console.log('您输入的统计排行前：' + val + '条')
      }
      resolve(val)
    })
  })
}

// 提示输入是否打印游标
const readShowLog = function () {
  return new Promise((resolve, reject) => {
    rl.question('请输入需要是否打印游标(默认1【0=否,1=是】)：', (answer) => {
      let val = answer.trim().toLocaleUpperCase()
      if (val === '') {
        console.log('使用默认打印游标：1')
        val = true
      } else {
        if (['0', '1'].indexOf(val) === -1) {
          reject('打印游标值不正确请输入0或1')
        }
        console.log('您输入的打印游标：' + val)
      }
      resolve(val)
    })
  })
}

async function init() {
  try {
    host = await readHost()
    port = await readPort()
    pwd = await readPwd()
    db = await readDb()
    leng = await readLeng()
    showLog = await readShowLog()
    //调用函数并打印结果
    let keys = await findLargestKey()
    const obj = {}
    keys = keys.map((item, index) => {
      item['KB'] = item['B'] / 1024
      item['MB'] = item['B'] / 1024 / 1024
      obj[index + 1] = item
      return item
    })
    console.log(`DB${db}使用内存排名前${leng}的KEYS:`, obj)
  } catch (err) {
    console.error('Error:', err)
    init()
  }
}

init()
